import { VisualizationEvent } from "../components/FeatureProcessor";

// 粒子类，表示爆炸效果中的单个粒子
class Particle {
  x: number;
  y: number;
  size: number;
  speedX: number;
  speedY: number;
  color: string;
  alpha: number;
  life: number; // 粒子生命周期
  decay: number; // 衰减速度

  constructor(x: number, y: number, color: string) {
    this.x = x;
    this.y = y;
    this.size = Math.random() * 8 + 2; // 减小粒子大小 2-10
    this.speedX = Math.random() * 4 - 2; // 减小水平速度 -2 到 2
    this.speedY = Math.random() * 4 - 2; // 减小垂直速度 -2 到 2
    this.color = color;
    this.alpha = 1;
    this.life = Math.random() * 30 + 30; // 生命周期 30-60 帧
    this.decay = Math.random() * 0.03 + 0.01; // 衰减速度 0.01-0.04
  }

  update() {
    this.x += this.speedX;
    this.y += this.speedY;
    this.alpha -= this.decay;
    this.life--;
  }

  draw(ctx: CanvasRenderingContext2D) {
    ctx.save();
    ctx.globalAlpha = this.alpha;
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
    ctx.fill();
    ctx.restore();
  }
}

export class ExplosionLayer {
  private canvas: HTMLCanvasElement;
  private ctx: CanvasRenderingContext2D;
  private isPlaying: boolean = false;
  private animationFrameId: number | null = null;
  private particles: Particle[] = [];
  private lastBeatTime: number = 0;
  private beatThreshold: number = 0.02; // 调整节拍检测阈值
  private beatCooldown: number = 0.5; // 增加节拍冷却时间(秒)至0.5秒

  constructor(canvas: HTMLCanvasElement) {
    this.canvas = canvas;
    const ctx = canvas.getContext('2d');
    if (!ctx) {
      throw new Error('Unable to get 2D context');
    }
    this.ctx = ctx;
  }

  public update(event: VisualizationEvent): void {
    if (!this.isPlaying) return;

    // 检测节拍并创建爆炸效果
    this.detectBeat(event);
    
    // 更新和绘制粒子
    this.updateParticles();
    this.draw();
  }

  private detectBeat(event: VisualizationEvent): void {
    const currentTime = event.time;
    
    // 使用 RMS 能量和过零率检测节拍
    const energy = event.rms * Math.pow(event.zeroCrossingRate, 0.5);
    
    // 添加调试日志
    // 每隔一定时间输出一次调试信息，避免日志过多
    if (Math.floor(currentTime * 2) % 10 === 0) { // 每5秒输出一次
      console.log(`ExplosionLayer: time=${currentTime.toFixed(2)}, rms=${event.rms.toFixed(4)}, zeroCrossingRate=${event.zeroCrossingRate.toFixed(4)}, energy=${energy.toFixed(4)}, threshold=${this.beatThreshold}`);
    }
    
    // 如果能量超过阈值且冷却时间已过，则触发爆炸
    if (energy > this.beatThreshold && (currentTime - this.lastBeatTime) > this.beatCooldown) {
      console.log(`Explosion triggered at time ${currentTime.toFixed(2)} with energy ${energy.toFixed(4)}`);
      this.createExplosion();
      this.lastBeatTime = currentTime;
    }
  }

  private createExplosion(): void {
    // 在随机位置创建爆炸，但避免在中心200像素范围内和边缘30像素内
    let x, y;
    const centerX = this.canvas.width / 2;
    const centerY = this.canvas.height / 2;
    const exclusionRadius = 100; // 中心排除半径100像素（直径200像素）
    const edgeMargin = 30; // 距离边缘的最小距离
    
    do {
      x = Math.random() * (this.canvas.width - edgeMargin * 2) + edgeMargin;
      y = Math.random() * (this.canvas.height - edgeMargin * 2) + edgeMargin;
      // 检查生成的位置是否在中心排除范围内
    } while (
      Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2)) < exclusionRadius
    );
    
    // 基于时间生成颜色
    const hue = (Date.now() / 10) % 360;
    const color = `hsl(${hue}, 100%, 60%)`;
    
    // 创建多个粒子形成爆炸效果，增加粒子数量
    const particleCount = Math.floor(Math.random() * 50) + 70; // 增加粒子数量到70-120个粒子
    
    for (let i = 0; i < particleCount; i++) {
      this.particles.push(new Particle(x, y, color));
    }
    
    console.log(`Created explosion with ${particleCount} particles at (${x.toFixed(0)}, ${y.toFixed(0)})`);
  }

  private updateParticles(): void {
    // 更新所有粒子
    for (let i = this.particles.length - 1; i >= 0; i--) {
      this.particles[i].update();
      
      // 移除生命周期结束的粒子
      if (this.particles[i].life <= 0 || this.particles[i].alpha <= 0) {
        this.particles.splice(i, 1);
      }
    }
  }

  private draw(): void {
    // 绘制所有粒子
    this.particles.forEach(particle => {
      particle.draw(this.ctx);
    });
  }

  public play(): void {
    this.isPlaying = true;
    this.animate();
  }

  public pause(): void {
    this.isPlaying = false;
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId);
      this.animationFrameId = null;
    }
  }

  private animate(): void {
    if (!this.isPlaying) return;
    this.animationFrameId = requestAnimationFrame(() => this.animate());
  }

  public resize(width: number, height: number): void {
    this.canvas.width = width;
    this.canvas.height = height;
  }
}